#pragma once

#include <map>
#include <list>
#include <algorithm> 
#include <functional>

#include "HTimerRunner.h"
#include "../base/HBaseDefine.h"

namespace timer {

template<class TString = std::wstring>
class HTimer {

public:
	HTimer(const HTimer& _rhs)
		: runner_(_rhs.runner_), helper_(_rhs.helper_) {}

	const HTimer& operator=(const HTimer& _rhs) {
		if (this != &_rhs) {
            helper_ = _rhs.helper_;
			runner_ = _rhs.runner_;
		}
		return *this;
	}
	~HTimer() {
        int i = 0;
        i += 3;
    }

public:
	inline HTimer& start(bool _immediately, bool* _result = NULL) {
        base::eec::shared_ptr<HTimerHelper<TString>> l_helper = helper_.lock();
        if (!l_helper) {
            return *this;
        }
		bool l_success = runner_->start_helper(l_helper->index(), _immediately);
		if (NULL != _result) {
			*_result = l_success;
		}
		return *this;
	}
	inline void stop() const {
        base::eec::shared_ptr<HTimerHelper<TString>> l_helper = helper_.lock();
        if (!l_helper) {
            return;
        }
        runner_->stop_helper(l_helper->index());
	}

public:
    inline unsigned long long index() const {
        base::eec::shared_ptr<HTimerHelper<TString>> l_helper = helper_.lock();
        if (!l_helper) {
            return 0;
        }
        return l_helper->index();
    }
	inline HTimer& times(int _times) {
        base::eec::shared_ptr<HTimerHelper<TString>> l_helper = helper_.lock();
        if (!l_helper || (HEnumTimerStaus::HETS_NULL != l_helper->status())) {
            return *this;
        }
        l_helper->times(_times);
		return *this;
	}
    int times() const { 
        base::eec::shared_ptr<HTimerHelper<TString>> l_helper = helper_.lock();
        if (!l_helper) {
            return 0;
        }
        return l_helper->times();
    }
    int trigger_times() const {
        base::eec::shared_ptr<HTimerHelper<TString>> l_helper = helper_.lock();
        if (!l_helper) {
            return 0;
        }
        return l_helper->trigger_times();
    }
	inline HTimer& type(HEnumTimeType _type) {
        base::eec::shared_ptr<HTimerHelper<TString>> l_helper = helper_.lock();
        if (!l_helper || (HEnumTimerStaus::HETS_NULL != l_helper->status())) {
            return *this;
        }
	    l_helper->type(_type);
		return *this;
	}
    HEnumTimeType type() const {
        base::eec::shared_ptr<HTimerHelper<TString>> l_helper = helper_.lock();
        if (!l_helper) {
            return HEnumTimeType::HTT_NULL;
        }
        return l_helper->type();
    }
	inline HTimer& exec(const EEC_STD::function<int()>& _exec) {
        base::eec::shared_ptr<HTimerHelper<TString>> l_helper = helper_.lock();
        if (!l_helper || (HEnumTimerStaus::HETS_NULL != l_helper->status())) {
            return *this;
        }
        l_helper->exec(_exec);
		return *this;
	}
    EEC_STD::function<int()> exec() const {
        base::eec::shared_ptr<HTimerHelper<TString>> l_helper = helper_.lock();
        if (!l_helper) {
            return NULL;
        }
        return l_helper->exec();
    }
	inline HTimer& desc(const TString& _desc) {
        base::eec::shared_ptr<HTimerHelper<TString>> l_helper = helper_.lock();
        if (!l_helper || (HEnumTimerStaus::HETS_NULL != l_helper->status())) {
            return *this;
        }
        l_helper->desc(_desc);
        return *this;
	}
    TString desc() const {
        base::eec::shared_ptr<HTimerHelper<TString>> l_helper = helper_.lock();
        if (!l_helper) {
            return L"";
        }
        return l_helper->desc();
    }
	inline HTimer& interval(const timer::microseconds& _interval) {
        base::eec::shared_ptr<HTimerHelper<TString>> l_helper = helper_.lock();
        if (!l_helper || (HEnumTimerStaus::HETS_NULL != l_helper->status())) {
            return *this;
        }
        l_helper->interval(_interval);
        return *this;
	}
    timer::microseconds interval() const {
        base::eec::shared_ptr<HTimerHelper<TString>> l_helper = helper_.lock();
        if (!l_helper) {
            return timer::microseconds(0);
        }
        return l_helper->interval();
    }

protected:
	HTimer(unsigned long long _index, const base::eec::shared_ptr<HTimerRunner<TString>>& _timer_runner)
		: runner_(_timer_runner), helper_(_timer_runner->new_helper(_index)) { }

private:
	base::eec::shared_ptr<HTimerRunner<TString>> runner_;
    base::eec::weak_ptr<HTimerHelper<TString>> helper_;

    template<class _TString>
	friend class HTimerManager;
};

#define fill_exec(vl) exec(__WFILE__, __LINE__, vl)

} // namespace base